package com.nulldev.util.web.HttpClient.clients.fuzzer;

import java.net.URL;
import java.time.Duration;
import java.util.List;
import java.util.Map;

import com.nulldev.util.concurrency.threadIt.v4.emapi.Tasks;
import com.nulldev.util.concurrency.threadIt.v4.emapi.uft.Executable;
import com.nulldev.util.data.Arrays.maps.FastMaps;
import com.nulldev.util.internal.backport.concurrency9.Lists;
import com.nulldev.util.web.HttpClient.HttpMethod;
import com.nulldev.util.web.HttpClient.HttpRequest;
import com.nulldev.util.web.HttpClient.HttpResponse;
import com.nulldev.util.web.HttpClient.ResponseFormat;
import com.nulldev.util.web.URLUtils.Entry;

public abstract class FuzzedHttpRequest<T> implements HttpRequest<T> {

	private String url;
	private final Map<String, String> headers = FastMaps.map(15);

	@Override
	public HttpRequest<T> url(final String url) throws Exception {
		this.url = url;
		return this;
	}

	@Override
	public HttpRequest<T> url(final URL url) throws Exception {
		this.url = url.toString();
		return this;
	}

	@Override
	public HttpRequest<T> header(final String key, final String value) {
		if (key == null || key.isEmpty())
			return this;
		if (value == null || value.isEmpty())
			return this;
		this.headers.put(key, value);
		return this;
	}

	@Override
	public HttpRequest<T> header(final Entry entry) {
		if (entry == null || !entry.isValid())
			return this;
		this.headers.put(entry.getKey(), entry.getValue());
		return this;
	}

	@Override
	public HttpRequest<T> headers(final Entry[] entries) {
		if (entries == null || entries.length == 0)
			return this;
		for (final Entry e : entries) {
			if (e == null)
				continue;
			this.header(e);
		}
		return this;
	}

	@Override
	public HttpRequest<T> forceHeader(final String key, final String value) {
		if (key == null || key.isEmpty())
			return this;
		if (value == null || value.isEmpty())
			return this;
		this.headers.put(key, value);
		return this;
	}

	@Override
	public HttpRequest<T> timeout(final Duration duration) {
		return this;
	}

	@Override
	public HttpResponse<T> create(final HttpMethod method, final Object body) throws Exception {
		return new FuzzedHttpRepsonse<T>(this.url, getFormat());
	}

	@Override
	public Executable<HttpResponse<T>> createTask(final HttpMethod method, final Object body) throws Exception {
		return Tasks.resolve(new FuzzedHttpRepsonse<T>(this.url, getFormat()));
	}

	@Override
	public boolean isSupportedMethod(final HttpMethod method) {
		return method != null;
	}

	@Override
	public HttpRequest<T> enableBuffering(final int bufferSize) {
		return this;
	}

	@Override
	public abstract ResponseFormat getFormat();

	/* Read API */

	@Override
	public String url() {
		return this.url;
	}

	@Override
	public Map<String, List<String>> headers() {
		final Map<String, List<String>> output = FastMaps.map(this.headers.size());
		for (final Map.Entry<String, String> e : this.headers.entrySet())
			output.put(e.getKey(), Lists.of(e.getValue()));
		return output;
	}

}
